using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Pvf.Core.Contents
{
    /// <summary>
    /// 
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    public sealed class ObjectMapperAttribute : Attribute
    {
        public ObjectMapperAttribute(string mapName)
        {
            MapName = mapName;
        }

        public string MapName { get; }
    }

    public interface IFieldOuter
    {

    }

    public enum MetaRegisterType
    {
        Object, Array, List
    }

    public abstract class MetaDescriptor : IScriptType
    {
        public abstract string UniqueName { get; }

        public bool EndOfStream(byte[] curr, ref int rawIndex)
        {
            if (curr.Length < 7) return true;
            if (rawIndex >= curr.Length) return true;
            if (rawIndex + 5 > curr.Length) return true;
            return false;
        }

        public bool IsValidByte(ref byte currentByte)
        {
            if (currentByte == 2 || currentByte == 4 || currentByte == 5 || currentByte == 6 || currentByte == 7 || currentByte == 8 || currentByte == 10)
            {
                return true;
            }
            return false;
        }

        public bool Next(byte[] unpackedStrBytes, ref int rawIndex, out byte currentByte, out int after1)
        {
            currentByte = 0;
            after1 = 0;
            if(rawIndex >= unpackedStrBytes.Length)
            {
                return false;
            }
            if (unpackedStrBytes.Length - rawIndex < 5)
            {
                return false;
            }
            int tIndex = rawIndex;
            rawIndex += 5;
            currentByte = unpackedStrBytes[tIndex];//猜测应该是内容指示位
            if (currentByte == 2 || currentByte == 4 || currentByte == 5 || 
                currentByte == 6 || currentByte == 7 || currentByte == 8 || 
                currentByte == 10)
            {
  
                after1 = BitConverter.ToInt32(unpackedStrBytes, tIndex + 1);
                return true;
            }
            return false;
        }

         protected int GetInt_2(byte curr, int after1, int before1)
        {
            return after1;
        }

        protected float GetFloat_4(byte curr, int after1, int before1)
        {
            return BitConverter.ToSingle(BitConverter.GetBytes(after1), 0);
        }

        protected string GetString_5_6_7_8(byte curr, int after1, int before1, IPvfEnv env)
        {
            return env.StringTable.TryGetValue(after1, out var foundValue) ? foundValue : "";
        }

        protected string GetString_10(byte curr, int after1, int before1, IPvfEnv env)
        {
            return !env.StringTable.TryGetValue(after1, out var foundValue) ? "" : $"<{before1}::{foundValue}`{GetNString(foundValue, env)}`>";
        }

        protected string GetNString(string str, IPvfEnv env)
        {
            return env.NStringTable.TryGetValue(str, out var foundValue) ? foundValue : "";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="instKey"></param>
        /// <param name="registerInfo"></param>
        /// <param name="env"></param>
        /// <param name="module"></param>
        /// <param name="unpackedStrBytes"></param>
        /// <param name="rawIndex"></param>
        /// <returns></returns>
        public abstract FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex);
    }

    public sealed class FStringMeta : MetaDescriptor
    {
        public override string UniqueName => "FString";

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            throw new NotImplementedException();
        }
    }

    public sealed class FRefStringMeta : MetaDescriptor
    {
        public override string UniqueName => throw new NotImplementedException();

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            throw new NotImplementedException();
        }
    }

    public sealed class FNameMeta : MetaDescriptor
    {
        public override string UniqueName => "FName";

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            while (true)
            {
                if (EndOfStream(unpackedStrBytes, ref rawIndex))
                {
                    break;
                }
                if (Next(unpackedStrBytes, ref rawIndex, out byte currentByte, out int after1))
                {
                    if (currentByte != 10) //是5的情况，stringbin[后面的整数]
                    {
                        continue;
                    }
                    if (!env.StringTable.TryGetValue(after1, out var foundValue))
                    {
                        throw new KeyNotFoundException($"字符串键未在StringTable中找到:{foundValue}");
                    }

                    if (module != null && module.Strings != null)
                    {
                        if (module.Strings.TryGetValue(foundValue, out var finalValue))
                        {
                            return new FName() { Value = finalValue };
                        }
                    }
                }
                else
                {
                    continue;
                }
            }
 
            return null;
        }
    }

    public sealed class FInt32Meta : MetaDescriptor
    {
        public override string UniqueName => "FInt32";

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            while (true)
            {
                if (EndOfStream(unpackedStrBytes, ref rawIndex))
                {
                    break;
                }
                if (Next(unpackedStrBytes, ref rawIndex, out byte currentByte, out int after1))
                {
                    if (currentByte != 2) //是5的情况，stringbin[后面的整数]
                    {
                        continue;
                    }
                    return new FInt32() { Value = after1 };
                }
                else
                {
                    continue;
                }
            }

            return null;
        }
    }

    public sealed class FFloatMeta : MetaDescriptor
    {
        public override string UniqueName => "FFloat";

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            while (true)
            {
                if (EndOfStream(unpackedStrBytes, ref rawIndex))
                {
                    break;
                }
                if (Next(unpackedStrBytes, ref rawIndex, out byte currentByte, out int after1))
                {
                    if (currentByte != 2) //是5的情况，stringbin[后面的整数]
                    {
                        continue;
                    }
                    return new FFloat32() { Value = BitConverter.ToSingle(BitConverter.GetBytes(after1), 0) };
                }
                else
                {
                    continue;
                }
            }
            return null;
        }
    }

    public sealed class FEnumInt32Meta : MetaDescriptor
    {
        public string UnderingType { get; set; }

        public override string UniqueName => "FEnumInt32";

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            while (true)
            {
                if (EndOfStream(unpackedStrBytes, ref rawIndex))
                {
                    break;
                }
                if (Next(unpackedStrBytes, ref rawIndex, out byte currentByte, out int after1))
                {
                    if (currentByte != 2) //是5的情况，stringbin[后面的整数]
                    {
                        continue;
                    }

                    return new FEnumInt32() { Value = after1 };
                }
                else
                {
                    continue;
                }
            }

            return null;
        }
    }

    public sealed class FEnumStringMeta : MetaDescriptor
    {
        public string UnderingType { get; set; }

        public override string UniqueName => "FEnumString";


        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            throw new NotImplementedException();
        }
    }

    public sealed class FObjectMeta : MetaDescriptor
    {
        public string FieldType { get; set; }

        public Type ObjType { get; set;}

        /// <summary>
        /// 所有字段都是必须的？如果是那么注册的时候不用填写字段名称
        /// </summary>
        /// <value></value>
        public bool FieldsIsRequired {get; set;}

        public override string UniqueName => string.IsNullOrWhiteSpace(FieldType) ? "UnnamedObject" : FieldType;

        private Dictionary<string, RegisterInfo> _descriptors = new Dictionary<string, RegisterInfo>(StringComparer.CurrentCultureIgnoreCase);


        public FObjectMeta()
        {
            
        }

        private void Push(FObject obj, ref BackFieldBase handled)
        {
            if (handled.Outer != obj)
            {
                return;
            }
            if (handled == null || string.IsNullOrWhiteSpace(handled.Name))
            {
                return;
            }

            obj.AddField(handled);
            handled = null;
        }

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            Type instType = ObjType == null ? typeof(FObject) : ObjType;
            if(instType == null){
                throw new NotSupportedException("");
            }

            //new object[] { env, module}
            var instObj = Activator.CreateInstance(instType) as FObject;
            if(instObj == null){
                throw new NullReferenceException("实例对象为空");
            }

            //如果有这个标识 表示每一个字段都是必须的
            if (FieldsIsRequired)
            {

            }
            else
            {
                while (true)
                {
                    if(EndOfStream(unpackedStrBytes, ref rawIndex))
                    {
                        break;
                    }
                    if(Next(unpackedStrBytes, ref rawIndex, out byte currentByte,out int after1))
                    {
                        if (currentByte != 5) //是5的情况，stringbin[后面的整数]
                        {
                            continue;
                        }
                        var str = GetString_5_6_7_8(currentByte, after1, 0, env);
                        if (str.StartsWith("[") && str.EndsWith("]"))
                        {
                            var subKey = str.Substring(1, str.Length - 2);
                            if (!_descriptors.TryGetValue(subKey, out var regInfo))
                            {
                                throw new KeyNotFoundException(str);
                            }

                            BackFieldBase backFieldBase;
                            if (regInfo.RegisterType == MetaRegisterType.Object)
                            {
                                backFieldBase = new BackField(subKey, instObj);
                            }
                            else
                            {
                                backFieldBase = new RangedBackField(subKey, instObj);
                            }

                            if (backFieldBase is BackField backField)
                            {
                                backField.Data = regInfo.Descriptor.CreateInstance(str, regInfo, env, module, unpackedStrBytes, ref rawIndex);
                            }
                            else if (backFieldBase is RangedBackField rangedBackField)
                            {
                                rangedBackField.Data = regInfo.Descriptor.CreateInstance(str, regInfo, env, module, unpackedStrBytes, ref rawIndex)
                                     as IEnumerable<FUnit>;
                            }

                            Push(instObj, ref backFieldBase);
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
            
            }
        
            return instObj;
        }

        public FObjectMeta Register(string name, MetaDescriptor meta, MetaRegisterType type = MetaRegisterType.Object)
        {
            var regInfo = new RegisterInfo()
            {
                Name = name,
                Index = _descriptors.Count,
                RegisterType = type,
                Descriptor = meta
            };

            if (string.IsNullOrWhiteSpace(regInfo.Name))
            {
                regInfo.Name = regInfo.Index.ToString();
            }
            _descriptors.Add(regInfo.Name, regInfo);

            return this;
        }
    }

    public sealed class TArrayMeta : MetaDescriptor
    {
        private readonly MetaDescriptor _itemMeta;

        public override string UniqueName => "TArray";

        public TArrayMeta(MetaDescriptor itemMeta)
        {
            _itemMeta = itemMeta;
        }

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            throw new NotImplementedException();
        }
    }

    public sealed class TListMeta : MetaDescriptor
    {
        private readonly MetaDescriptor _itemMeta;

        public override string UniqueName => "TList";

        public TListMeta(MetaDescriptor itemMeta)
        {
            _itemMeta = itemMeta;
        }

        public override FUnit CreateInstance(string instKey, RegisterInfo registerInfo, IPvfEnv env, IPvfModule module, byte[] unpackedStrBytes, ref int rawIndex)
        {
            throw new NotImplementedException();
        }
    }

    public class RegisterInfo
    {
        /// <summary>
        /// 
        /// </summary>
        public int Index { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public MetaDescriptor Descriptor { get; set; }

        /// <summary>
        /// 注册名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 注册类型
        /// </summary>
        public MetaRegisterType RegisterType { get; set; }

        /// <summary>
        /// Array固定长度
        /// </summary>
        public int FixedLength { get; set; }
    }

    public abstract class BackFieldBase
    {
        /// <summary>
        /// 
        /// </summary>
        /// <value></value>
        public IFieldOuter Outer { get; protected set; }

        /// <summary>
        /// 
        /// </summary>
        /// <value></value>
        public string Name { get; protected set; }

        public abstract bool IsArray { get; }
    }

    /// <summary>
    /// 数组
    /// </summary>
    public class RangedBackField : BackFieldBase
    {
        public override bool IsArray => true;

        /// <summary>
        /// 
        /// </summary>
        /// <value></value>
        public IEnumerable<FUnit> Data { get; internal set; }

        public RangedBackField(string instKey, IFieldOuter outer)
        {
            Name = instKey;
            Outer = outer;
        }

    }

    /// <summary>
    /// 对象
    /// </summary>
    public sealed class BackField : BackFieldBase
    {
        public override bool IsArray => false;

        /// <summary>
        /// 
        /// </summary>
        /// <value></value>
        public FUnit Data { get; internal set; }

        public BackField(string instKey, IFieldOuter outer)
        {
            Name = instKey;
            Outer = outer;
        }
    }

    public abstract class FUnit
    {

    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TPrimaryType"></typeparam>
    public abstract class FUnit<TPrimaryType> : FUnit
    {
        private TPrimaryType _field;

        /// <summary>
        /// 
        /// </summary>
        /// <value></value>
        public TPrimaryType Value
        {
            get { return _field; }
            set { _field = value; }
        }

        private bool _init = false;

        public virtual void Init(TPrimaryType initValue)
        {
            if (_init)
            {
                return;
            }
            _init = true;
            _field = initValue;
        }
    }

    public class FObject : FUnit<FObject>, IFieldOuter
    {
        /// <summary>
        /// 成员对象(MetaTable)
        /// </summary>
        /// <typeparam name="string"></typeparam>
        /// <typeparam name="UnitObject"></typeparam>
        /// <returns></returns>
        private Dictionary<string, BackFieldBase> _fields;

        internal void AddField(BackFieldBase field)
        {
            if(_fields == null)
            {
                _fields = new Dictionary<string,BackFieldBase>();
            }
            _fields.Add(field.Name, field);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEle"></typeparam>
    public class TArray<TEle> : FUnit, IEnumerable<TEle>
        where TEle:FUnit
    {
        public IEnumerator<TEle> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEle"></typeparam>
    public class TList<TEle> : FUnit, IEnumerable<TEle>
        where TEle:FUnit
    {
        public IEnumerator<TEle> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// 字符串
    /// </summary>
    public class FString : FUnit<string>
    {

    }

    /// <summary>
    /// 浮点型
    /// </summary>
    public class FFloat32 : FUnit<float>
    {

    }

    /// <summary>
    /// 整型
    /// </summary>
    public class FInt32 : FUnit<int>
    {

    }

    /// <summary>
    /// 名字
    /// </summary>
    public class FName : FUnit<string>
    {

    }

    /// <summary>
    /// 枚举
    /// </summary>
    public class FEnumInt32 : FUnit<int>
    {

    }

    /// <summary>
    /// 枚举(字符串)
    /// </summary>
    public class FEnumString : FUnit<string>
    {
    }

    public class FEnumFlag: FUnit<string[]>
    {
        public bool AnyValue { get; set; }
    }

    /// <summary>
    /// 字符串
    /// </summary>
    public class FRefString : FUnit<string>
    {
        
    }

    public sealed class  EnumItem
    {
        public int Key{get;set;}

        public string Value{get;set;}

        public string Desc{get;set;}

        private EnumItem(int key, string value,string desc=""){
            Key = key;
            Value = value;
            Desc = desc;
        }

        public static EnumItem Create(int key,string value,string desc=""){
            return new EnumItem(key,value,desc);
        }
    }

    public class EnumSource : IScriptType
    {
        private string _enumName = "";
        private Dictionary<int, EnumItem> _enumValues;

        public string UniqueName => _enumName;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="enumName"></param>
        /// <param name="enumValues"></param>
        /// <returns></returns>
        public static EnumSource Create(string enumName, params EnumItem[] enumValues)
        {
            
            var es = new EnumSource()
            {
                _enumName = enumName,
                _enumValues = new Dictionary<int, EnumItem>()
            };

            foreach (var enumItem in enumValues)
            {
                es._enumValues.Add(enumItem.Key, enumItem);
            }

            return es;
        }
    }


    public sealed class PvfScriptObjectContent<TObj> : PvfContent<TObj>
        where TObj: FObject
    {
        private TObj _data = null;
        public override TObj Data => _data;

        public PvfScriptObjectContent()
        {
                  
        }

        private void Init()
        {
           

        }

        public override bool Load(Encoding encoding, IPvfModule module)
        {
            if (Data != null)
            {
                return true;
            }

            if (!base.Load(encoding, module))
            {
                return false;
            }

            Init();

            int rawIndex = 2;

            var objMeta = Index.Env.VM.GetMetaSource<FObjectMeta>(typeof(TObj).Name.ToLower());

            var loadedObj = objMeta.CreateInstance(null, null, Index.Env, module, BytesData, ref rawIndex) as TObj;

            _data = loadedObj;

            return true;
        }
    }
}
